package com.xiaoshuidi.cloud.module.report.service.finance;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.oss.core.OosFileService;
import com.xiaoshuidi.cloud.framework.security.core.LoginUser;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.contract.api.ContractTaxRateApi;
import com.xiaoshuidi.cloud.module.contract.vo.ContractTaxRateVO;
import com.xiaoshuidi.cloud.module.report.controller.finance.vo.*;
import com.xiaoshuidi.cloud.module.report.convert.finance.IncomeDetailConvert;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.IncomeDetailReportDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.IncomeSummaryReportDO;
import com.xiaoshuidi.cloud.module.report.dal.mapper.report.IncomeDetailReportMapper;
import com.xiaoshuidi.cloud.module.report.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.report.framework.security.config.ConfigValues;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
@Slf4j
public class IncomeDetailReportServiceImpl implements IncomeDetailReportService {

    private final IncomeDetailReportMapper incomeDetailReportMapper;
    private final OosFileService oosFileService;
    private final ConfigValues configValues;
    @Resource
    private ContractTaxRateApi contractTaxRateApi;

    @Override
    public PageResult<DetailIncomePageRespVO> detailIncomePage(DetailIncomePageReqVO reqVO) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if(loginUser==null){
            throw new ServiceException(ErrorCodeConstants.USER_NOT_LOGIN);
        }
        reqVO.setTenantId(loginUser.getTenantId());
        long num = incomeDetailReportMapper.countListForPage(reqVO);
        List<IncomeDetailReportDO> detailReports = incomeDetailReportMapper.selectListForPage(reqVO);
        List<DetailIncomePageRespVO> pageResps = IncomeDetailConvert.INSTANCE.convertDetailIncomePage(detailReports);
        pageResps.forEach(e->{
            List<IncomeDetailReportDO> incomeDetailReportDOS = incomeDetailReportMapper.selectListByContractIdAndStatisMonth(e.getStatisticsMonth(), e.getRoomId());
            List<ContractDetailsRespVO> pageRespVOS = IncomeDetailConvert.INSTANCE.convertDetailForContract(incomeDetailReportDOS);

            pageRespVOS.forEach(item->{
                //税率
                CommonResult<ContractTaxRateVO> contractTaxRate = contractTaxRateApi.getContractTaxRate(item.getApartmentId());
                ContractTaxRateVO data = contractTaxRate.getData();
                if(data != null){
                    JSONArray objects = JSONUtil.parseArray(data.getContent());
                    Map<String, List<Object>> type = objects.stream().collect(Collectors.groupingBy(json -> JSONUtil.parseObj(json.toString()).getStr("type")));
                    //本期租金收入
                    JSONObject curRentIn = calculatedTax("租金", item.getCurRentIn(), type);
                    item.setCurRentInVAT(curRentIn.getBigDecimal("vat"));
                    item.setCurRentInNotTax(curRentIn.getBigDecimal("notTax"));
                    //本期租金折扣
                    JSONObject curRentDisc = calculatedTax("租金", item.getCurRentDisc(), type);
                    item.setCurRentDiscVAT(curRentDisc.getBigDecimal("vat"));
                    item.setCurRentDiscNotTax(curRentDisc.getBigDecimal("notTax"));
                    //累计租金收入
                    JSONObject accRentInVAT = calculatedTax("租金", item.getAccRentIn(), type);
                    item.setAccRentInVAT(accRentInVAT.getBigDecimal("vat"));
                    item.setAccRentInNotTax(accRentInVAT.getBigDecimal("notTax"));
                    //累计租金折扣
                    JSONObject accRentDisc = calculatedTax("租金", item.getAccRentDisc(), type);
                    item.setAccRentDiscVAT(accRentDisc.getBigDecimal("vat"));
                    item.setAccRentDiscNotTax(accRentDisc.getBigDecimal("notTax"));
                    //本期其他收入
                    JSONObject curOtherIn = calculatedTax("其他收入", item.getCurOtherIn(), type);
                    item.setCurOtherInVAT(curOtherIn.getBigDecimal("vat"));
                    item.setCurOtherInNotTax(curOtherIn.getBigDecimal("notTax"));
                    //本期其他折扣
                    JSONObject curOtherDisc = calculatedTax("其他收入", item.getCurOtherDisc(), type);
                    item.setCurOtherDiscVAT(curOtherDisc.getBigDecimal("vat"));
                    item.setCurOtherDiscNotTax(curOtherDisc.getBigDecimal("notTax"));
                    //累计其他收入
                    JSONObject accOtherIn = calculatedTax("其他收入", item.getAccOtherIn(), type);
                    item.setAccOtherInVAT(accOtherIn.getBigDecimal("vat"));
                    item.setAccOtherInNotTax(accOtherIn.getBigDecimal("notTax"));
                    //累计其他折扣
                    JSONObject accOtherDisc = calculatedTax("其他收入", item.getAccOtherDisc(), type);
                    item.setAccOtherDiscVAT(accOtherDisc.getBigDecimal("vat"));
                    item.setAccOtherDiscNotTax(accOtherDisc.getBigDecimal("notTax"));
                }else {
                    //本期租金收入
                    item.setCurRentInVAT(new BigDecimal(0));
                    item.setCurRentInNotTax(item.getCurRentIn());
                    //本期租金折扣
                    item.setCurRentDiscVAT(new BigDecimal(0));
                    item.setCurRentDiscNotTax(item.getCurRentDisc());
                    //累计租金收入
                    item.setAccRentInVAT(new BigDecimal(0));
                    item.setAccRentInNotTax(item.getAccRentIn());
                    //累计租金折扣
                    item.setAccRentDiscVAT(new BigDecimal(0));
                    item.setAccRentDiscNotTax(item.getAccRentDisc());
                    //本期其他收入
                    item.setCurOtherInVAT(new BigDecimal(0));
                    item.setCurOtherInNotTax(item.getCurOtherIn());
                    //本期其他折扣
                    item.setCurOtherDiscVAT(new BigDecimal(0));
                    item.setCurOtherDiscNotTax(item.getCurOtherDisc());
                    //累计其他收入
                    item.setAccOtherInVAT(new BigDecimal(0));
                    item.setAccOtherInNotTax(item.getAccOtherIn());
                    //累计其他折扣
                    item.setAccOtherDiscVAT(new BigDecimal(0));
                    item.setAccOtherDiscNotTax(item.getAccOtherDisc());
                }
            });
            e.setContractDetails(pageRespVOS);
        });
        return new PageResult<>(pageResps,num);
    }

    /**
     * 计算税率
     * @param text
     * @param money
     * @param type
     * @return
     */
    private JSONObject calculatedTax(String text, BigDecimal money, Map<String, List<Object>> type){
        JSONObject entries = new JSONObject();
        if (type.containsKey(text)) {
            JSONArray objects = JSONUtil.parseArray(type.get(text));
            JSONObject jsonObject = objects.getJSONObject(0);
            BigDecimal taxRate = jsonObject.getBigDecimal("taxRate");
            BigDecimal vat = money.multiply(taxRate).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal notTax = money.subtract(vat);
            entries.putOpt("vat",vat);
            entries.putOpt("notTax",notTax);
        }else{
            entries.putOpt("vat","0");
            entries.putOpt("notTax",money);
        }
        return entries;
    }


    @Override
    public ExportRespVO detailIncomeExport(DetailIncomePageReqVO req) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if(loginUser==null){
            throw new ServiceException(ErrorCodeConstants.USER_NOT_LOGIN);
        }
        req.setTenantId(loginUser.getTenantId());
        //暂时不分页，当月合同数不会超过2000
        String fileName =  req.getStatisticsMonth() + "收入汇总明细表.xlsx";
        String filePath = configValues.getNfsPath() + File.separator +fileName;
        ExcelWriter excelWriter = EasyExcel.write(filePath, DetailIncomeExportRespVO.class).build();
        WriteSheet sheet = EasyExcel.writerSheet("sheet1").build();
        List<IncomeDetailReportDO> reportDOList = incomeDetailReportMapper.selectListForExport(req);
        if(CollectionUtils.isEmpty(reportDOList)){
            throw new ServiceException(ErrorCodeConstants.DETAIL_INCOME_NOT_EXISTS);
        }
        List<DetailIncomeExportRespVO> list =IncomeDetailConvert.INSTANCE.convertDetailForExport(reportDOList);
        excelWriter.write(list, sheet);
        excelWriter.finish();
        //上传到oos返回URL
        String url = oosFileService.oosUploadFile(new File(filePath));
        ExportRespVO resp = new ExportRespVO();
        if(url.startsWith("http:")){
            url = url.replace("http:","https:");
        }
        resp.setUrl(url);
        resp.setFileName(fileName);
        return resp;
    }

    @Override
    public IncomeDetailReportDO getRecentIncomeReport(Long contractId,String currentMonth) {
        LambdaQueryWrapper<IncomeDetailReportDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IncomeDetailReportDO::getContractId, contractId);
        queryWrapper.lt(IncomeDetailReportDO::getStatisticsMonth,currentMonth);
        queryWrapper.orderByDesc(IncomeDetailReportDO::getId);
        queryWrapper.last("limit 1");
        List<IncomeDetailReportDO> incomeDetailReportDOS = incomeDetailReportMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(incomeDetailReportDOS)) {
            return null;
        }
        return incomeDetailReportDOS.get(0);
    }

    @Override
    public long countDetailsInCurrentMonth(String currentMonth) {
        return incomeDetailReportMapper.countDetailsInCurrentMonth(currentMonth);
    }

    @Override
    public List<IncomeDetailReportDO> selectDetailsInCurrentMonth(String currentMonth) {
        LambdaQueryWrapper<IncomeDetailReportDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IncomeDetailReportDO::getStatisticsMonth, currentMonth);
        return incomeDetailReportMapper.selectList(queryWrapper);
    }

    @Override
    public List<IncomeDetailReportDO> selectDetailsInCurrentMonthInTurn(String currentMonth,Integer from,Integer pageSize) {
        LambdaQueryWrapper<IncomeDetailReportDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IncomeDetailReportDO::getStatisticsMonth, currentMonth);
        queryWrapper.orderByAsc(IncomeDetailReportDO::getId);
        queryWrapper.last("limit "+from+","+pageSize);
        return incomeDetailReportMapper.selectList(queryWrapper);
    }

    @Override
    public IncomeDetailReportDO selectDetailsByContractIdInCurrentMonth(Long contractId, String currentMonth) {
        return incomeDetailReportMapper.selectDetailsByContractIdInCurrentMonth(contractId,currentMonth);
    }

    @Override
    public BigDecimal sumTotalRentAndWaterByContractId(Long contractId) {
        return incomeDetailReportMapper.sumTotalRentAndWaterByContractId(contractId);
    }

    @Override
    public void insertBatch(List<IncomeDetailReportDO> list){
        incomeDetailReportMapper.insertBatch(list);
    }
    @Override
    public void updateBatch(List<IncomeDetailReportDO> list){
        incomeDetailReportMapper.updateBatch(list,list.size());
    }

    @Override
    public List<IncomeDetailReportDO> selectDetailsInCurrentMonthAndContractIds(String currentMonth, List<Long> contractIds) {
        LambdaQueryWrapper<IncomeDetailReportDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IncomeDetailReportDO::getStatisticsMonth, currentMonth);
        queryWrapper.in(IncomeDetailReportDO::getContractId,contractIds);
        return incomeDetailReportMapper.selectList(queryWrapper);
    }

    @Override
    public List<IncomeSummaryReportDO> selectDetailsInCurrentMonthGroupByApartmentId(String currentMonth){
       return incomeDetailReportMapper.selectDetailsInCurrentMonthGroupByApartmentId(currentMonth);
    }


}
